//
//  CBEmotionView.m
//  CBEmotionView
//
//  Created by ly on 8/21/13.
//  Copyright (c) 2013 ly. All rights reserved.
//

#import "CBEmotionView.h"
#import <CoreText/CoreText.h>
#import "CBRegularExpressionManager.h"
#import "NSString+CBExtension.h"
#import "NSArray+CBExtension.h"
#import "CHEmotionHelper.h"
#import "MicroDef.h"
#import "WebViewController.h"
#import "CBEmotionView.h"
#import "AppDelegate.h"
#import "CBTextCheckingResult.h"

#define EmotionItemPattern          @"\\[([^\\[\\]]*)\\]"
#define PlaceHolder                 @" "
#define EmotionFileType             @"png"
#define AttributedImageNameKey      @"ImageName"
#define kCharacterSpacing           1.0
//#define kFontSize                   16.0
//#define EmotionImageWidth           kFontSize+4.0
//#define FontHeight                  kFontSize
#define ImageLeftPadding            2.0
#define ImageTopPadding             4.0
static NSInteger kPhoneSheetTag = 1000;

@interface CBEmotionView ()<UIActionSheetDelegate>
{
    dispatch_queue_t    queue;
    dispatch_group_t    group;
    CTTypesetterRef     _typesetter;
    
    UIColor             *_textColor;
    CBTextCheckingResult* _activeLink;

}

@property (nonatomic, retain) UIColor *textColor;
@property (nonatomic, assign) CTTypesetterRef typesetter;
@property (nonatomic, retain) NSMutableArray *linkDetectorArr;
@property (nonatomic, retain) NSMutableArray *drawLinesArr;
@end

@implementation CBEmotionView
@synthesize emotionString = _emotionString;
@synthesize emotionRanges = _emotionRanges;
@synthesize emotionNames = _emotionNames;
@synthesize typesetter = _typesetter;
@synthesize textColor = _textColor;
@synthesize attrEmotionString = _attrEmotionString;
@synthesize selectedToShowCopyMenu;
- (void)dealloc
{
//    NSLog(@"CBEmotionView dealloc");
    CFRelease(_typesetter);
}
//- (id)initWithCoder:(NSCoder *)aDecoder
//{
//    self = [super initWithCoder:aDecoder];
//    if (self) {
////        _emotionString = @"";
////        [self setup];
//    }
//    return self;
//}

//- (id)initWithFrame:(CGRect)frame
//{
//    self = [super initWithFrame:frame];
//    if (self) {
////        _emotionString = @"";
////        [self setup];
//    }
//    return self;
//}

- (id)initWithFrame:(CGRect)frame emotionString:(NSString *)emotionString textColor:(UIColor *)color
{
    self = [super initWithFrame:frame];
    if (self) {
        self.textColor = color;
        self.emotionString = emotionString;
        self.linkDetectorArr = [NSMutableArray array];
        self.drawLinesArr = [NSMutableArray array];
        [self setup];
    }
    return self;
}

- (void)setup
{
    queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    group = dispatch_group_create();
    [self prepare];
}

- (void)prepare
{
    self.backgroundColor = [UIColor clearColor];
    [self cookEmotionString];
}

#pragma mark - Cook the emotion string
- (void)cookEmotionString
{
    // 使用正则表达式查找特殊字符的位置
    __block NSArray *itemIndexes = [CBRegularExpressionManager itemIndexesWithPattern:EmotionItemPattern inString:_emotionString];
    
    __block NSArray *names = nil;
    __block NSString *newString = nil;
    __block NSArray *newRanges = nil;
    
    dispatch_group_async(group, queue, ^{
        // 查找表情对应的字符串 并加载相应的表情图片到内存中
        names = [_emotionString itemsForPattern:EmotionItemPattern captureGroupIndex:0];
    });
    dispatch_group_async(group, queue, ^{
        // 将 emotionString 中的特殊字符串替换为空格
        newString = [_emotionString replaceCharactersAtIndexes:itemIndexes withString:PlaceHolder];
    });
    dispatch_group_async(group, queue, ^{
        // 新的表情的占位符的 range 数组
        newRanges = [itemIndexes offsetRangesInArrayBy:[PlaceHolder length]];
    });
    
    dispatch_group_notify(group, queue, ^{
        _emotionNames = names;
        
        _emotionRanges = newRanges;

        _attrEmotionString = [self createAttributedEmotionStringWithRanges:newRanges
                                                                 forString:newString];
        // 创建typesetter 太耗费时间，所以在 typesetter 创建的时间提前到绘图前
        _typesetter = CTTypesetterCreateWithAttributedString((CFMutableAttributedStringRef)
                                               (_attrEmotionString));
        
        dispatch_async(dispatch_get_main_queue(), ^{
            [self setNeedsDisplay];

        });
    });
    //dispatch_release(group);
}

#pragma mark - Utility for emotions relative operations
// 根据调整后的字符串，生成绘图时使用的 attribute string
- (NSMutableAttributedString *)createAttributedEmotionStringWithRanges:(NSArray *)ranges
                                                      forString:(NSString*)aString
{
//    NSAssert(_emotionString != nil, @"emotionString 不可以为Nil");
//    NSAssert(aString != nil,        @"aString 不可以为Nil");
//
    NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:aString];
    int count = [ranges count];
    for(NSInteger i = 0; i < count; i++)
    {
        NSRange range = [[ranges objectAtIndex:i] rangeValue];
        NSString *emotionName = [self.emotionNames objectAtIndex:i];
        [attrString addAttribute:AttributedImageNameKey value:emotionName range:range];
        
        CTRunDelegateCallbacks imageCallbacks;
        imageCallbacks.version = kCTRunDelegateVersion1;
        imageCallbacks.dealloc = RunDelegateDeallocCallback;
        imageCallbacks.getAscent = RunDelegateGetAscentCallback;
        imageCallbacks.getDescent = RunDelegateGetDescentCallback;
        imageCallbacks.getWidth = RunDelegateGetWidthCallback;
        CTRunDelegateRef runDelegate = CTRunDelegateCreate(&imageCallbacks,(__bridge void *)(emotionName));
        [attrString addAttribute:(NSString *)kCTRunDelegateAttributeName value:(__bridge id)(runDelegate) range:range];
        CFRelease(runDelegate);
    }
    //设置字体大小
    CGFloat fontSize = [USER_DEFAULT floatForKey:@"messageFontSize"];
    CTFontRef theFont = CTFontRefCTFontCreateFromUIFont([UIFont systemFontOfSize:fontSize]);
    
    CFAttributedStringSetAttribute((CFMutableAttributedStringRef)(attrString),
                                   CFRangeMake(0,CFAttributedStringGetLength((CFAttributedStringRef)(attrString))),
                                   kCTFontAttributeName,
                                   theFont);
    
    CFAttributedStringSetAttribute((CFMutableAttributedStringRef)(attrString),
                                   CFRangeMake(0,CFAttributedStringGetLength((CFAttributedStringRef)(attrString))),
                                   kCTForegroundColorAttributeName,
                                   self.textColor.CGColor);
    
    CFRelease(theFont);
    
    
    //设置字间距
    long number = kCharacterSpacing;
    CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
    [attrString addAttribute:(id)kCTKernAttributeName value:(__bridge id)num range:NSMakeRange(0,CFAttributedStringGetLength((CFAttributedStringRef)(attrString)))];
    CFRelease(num);
    attrString = [self attributedTextWithLinksWithStr:attrString];
    return attrString;
}
//添加下划线
-(NSMutableAttributedString*)attributedTextWithLinksWithStr:(NSMutableAttributedString *)attrString
{
    NSMutableAttributedString* str = [attrString mutableCopy];
    if (!str) return nil;
    
//    NSTextCheckingTypes automaticallyAddLinksForType  = NSTextCheckingTypeLink|NSTextCheckingTypePhoneNumber;
    NSString* plainText = [str string];
    if (plainText )
    {
        NSError* error = nil;
//        NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:automaticallyAddLinksForType error:&error];
//        [linkDetector enumerateMatchesInString:plainText options:0 range:NSMakeRange(0,[plainText length])
//                                    usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
//         {
//             [self.linkDetectorArr addObject:result];
//             [str removeAttribute:(NSString*)kCTForegroundColorAttributeName range:[result range]]; // Work around for Apple leak
//             [str addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)[UIColor blueColor].CGColor range:[result range]];
////
//             [str removeAttribute:(NSString*)kCTUnderlineStyleAttributeName range:[result range]]; // Work around for Apple leak
//             [str addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:[result range]];
//         }];
        NSRegularExpression *urlRegex = [NSRegularExpression regularExpressionWithPattern: @"((http[s]{0,1}|ftp|items)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|((www.)?([a-zA-Z0-9\\-]+\\.)+([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(((http[s]{0,1}|ftp)://)?(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\\.((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){2}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)" options:NSRegularExpressionCaseInsensitive error:&error];
       
        
        [urlRegex enumerateMatchesInString:plainText options:0 range:NSMakeRange(0, [plainText length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
            
            
            CBTextCheckingResult *temp = [[CBTextCheckingResult alloc] init];
            temp.resultType = NSTextCheckingTypeLink;
            temp.selectStr =  [plainText substringWithRange:result.range];
            
            temp.range = result.range;
            [self.linkDetectorArr addObject:temp];
            [str removeAttribute:(NSString*)kCTForegroundColorAttributeName range:[result range]]; // Work around for Apple leak
            [str addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)RGBCOLORWITH16COLOR(0x1e628f).CGColor range:[result range]];
            [str removeAttribute:(NSString*)kCTUnderlineStyleAttributeName range:[result range]]; // Work around for Apple leak
            [str addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:[result range]];

//            [NSTextCheckingResult linkCheckingResultWithRange:result.range URL:[NSURL URLWithString:temp.selectStr]];
        }];
        
        NSRegularExpression *phoneNumber = [NSRegularExpression regularExpressionWithPattern: @"\\d{3}-\\d{8}|\\d{3}-\\d{7}|\\d{4}-\\d{8}|\\d{4}-\\d{7}|1+[358]+\\d{9}|\\d{8}|\\d{7}" options:0 error:&error];
        [phoneNumber enumerateMatchesInString:plainText options:0 range:NSMakeRange(0, [plainText length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
            CBTextCheckingResult *temp = [[CBTextCheckingResult alloc] init];
            temp.resultType = NSTextCheckingTypePhoneNumber;
            temp.selectStr =  [plainText substringWithRange:result.range];
            temp.range = result.range;
            [self.linkDetectorArr addObject:temp];
            [str removeAttribute:(NSString*)kCTForegroundColorAttributeName range:[result range]]; // Work around for Apple leak
            [str addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)RGBCOLORWITH16COLOR(0x1e628f).CGColor range:[result range]];
            [str removeAttribute:(NSString*)kCTUnderlineStyleAttributeName range:[result range]]; // Work around for Apple leak
            [str addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:[result range]];
//            [NSTextCheckingResult phoneNumberCheckingResultWithRange:result.range phoneNumber:temp.selectStr];
        }];

    }
    return str;
}

CTFontRef CTFontRefCTFontCreateFromUIFont(UIFont *font)
{
    CTFontRef ctFont =CTFontCreateWithName((CFStringRef)font.fontName,
                                           font.pointSize,
                                           NULL);
    return ctFont;
}

// 通过表情名获得表情的图片
- (UIImage *)getEmotionForKey:(NSString *)key
{
    CHEmotionHelper *helper =[CHEmotionHelper sharedInstance];
    EMotionModel *model = [helper getFileNameByWord:key];
    
    
    if (model) {
        
        return [UIImage imageNamed:[NSString stringWithFormat:@"%@/%@",model.directory,model.png]];
    } else {
        return nil;
    }
}

//CTRunDelegateRef newEmotionRunDelegate()
//{
//    static NSString *emotionRunName = @"com.cocoabit.CBEmotionView.emotionRunName";
//    
//    CTRunDelegateCallbacks imageCallbacks;
//    imageCallbacks.version = kCTRunDelegateVersion1;
//    imageCallbacks.dealloc = RunDelegateDeallocCallback;
//    imageCallbacks.getAscent = RunDelegateGetAscentCallback;
//    imageCallbacks.getDescent = RunDelegateGetDescentCallback;
//    imageCallbacks.getWidth = RunDelegateGetWidthCallback;
//    CTRunDelegateRef runDelegate = CTRunDelegateCreate(&imageCallbacks,
//                                   (__bridge void *)(emotionRunName));
//    
//    return runDelegate;
//}

#pragma mark - Run delegate
void RunDelegateDeallocCallback( void* refCon )
{
    // Do nothing here
}

CGFloat RunDelegateGetAscentCallback( void *refCon )
{
//    return FontHeight+10;
    return [USER_DEFAULT floatForKey:@"messageFontSize"] + 10;
}

CGFloat RunDelegateGetDescentCallback(void *refCon)
{
    return 0.0;
}

CGFloat RunDelegateGetWidthCallback(void *refCon)
{
    // EmotionImageWidth + 2 * ImageLeftPadding
//    return  EmotionImageWidth + 2 * ImageLeftPadding;
    return [USER_DEFAULT floatForKey:@"messageFontSize"] +4 + 2*ImageLeftPadding;
}

#pragma mark - Drawing
- (void)drawRect:(CGRect)rect
{
    // 没有内容时取消本次绘制
    if (!_typesetter)   return;
    
    CGFloat w = CGRectGetWidth(self.frame);
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 保存 context 信息
    CGContextSaveGState(context);
    
    // 翻转坐标系
//    Flip_Context(context, FontHeight);
    Flip_Context(context, [USER_DEFAULT floatForKey:@"messageFontSize"]);
    
    CGFloat y = 0;
    CFIndex start = 0;
    NSInteger length = [_attrEmotionString length];
    if ([self.drawLinesArr count]) {
        [self.drawLinesArr removeAllObjects];
    }
    while (start < length)
    {
        CFIndex count = CTTypesetterSuggestClusterBreak(_typesetter, start, w);
        
        CTLineRef line = CTTypesetterCreateLine(_typesetter, CFRangeMake(start, count));
        
        CGContextSetTextPosition(context, 0, y);
        // 画字
        CTLineDraw(line, context);  
        
        // 画表情
        Draw_Emoji_For_Line(context, line, self, CGPointMake(0, y)); 
        
        start += count;
//        y -= kFontSize + 4.0;
        NSDictionary *dic = @{@"y":[NSNumber numberWithFloat:y],@"line":(__bridge id)(line)};
        [self.drawLinesArr addObject:dic];
//        y-=EmotionImageWidth;
        y-=[USER_DEFAULT floatForKey:@"messageFontSize"]+4;
        CFRelease(line);
    }

    // 恢复 context 信息
    CGContextRestoreGState(context);
}

+(CGSize)getTextHeightWithEmotionString:(NSString *)emotionString maxWidth:(CGFloat)mWidth
{
    NSArray *itemIndexes = [CBRegularExpressionManager itemIndexesWithPattern:EmotionItemPattern inString:emotionString];
    
    CTTypesetterRef typesetter = NULL;
    NSArray *names = nil;
    NSString *newString = nil;
    NSArray *newRanges = nil;
    NSMutableAttributedString *attrEmotionString = nil;
    names = [emotionString itemsForPattern:EmotionItemPattern captureGroupIndex:0];
    newString = [emotionString replaceCharactersAtIndexes:itemIndexes withString:PlaceHolder];
    newRanges = [itemIndexes offsetRangesInArrayBy:[PlaceHolder length]];
    if(newString == nil)
    {
        newString = @"";
    }
    
    attrEmotionString = [[NSMutableAttributedString alloc] initWithString:newString];
    int count = [newRanges count];
    for(NSInteger i = 0; i < count; i++)
    {
        NSRange range = [[newRanges objectAtIndex:i] rangeValue];
        NSString *emotionName = [names objectAtIndex:i];
        [attrEmotionString addAttribute:AttributedImageNameKey value:emotionName range:range];
        
        CTRunDelegateCallbacks imageCallbacks;
        imageCallbacks.version = kCTRunDelegateVersion1;
        imageCallbacks.dealloc = RunDelegateDeallocCallback;
        imageCallbacks.getAscent = RunDelegateGetAscentCallback;
        imageCallbacks.getDescent = RunDelegateGetDescentCallback;
        imageCallbacks.getWidth = RunDelegateGetWidthCallback;
        CTRunDelegateRef runDelegate = CTRunDelegateCreate(&imageCallbacks,(__bridge void *)(emotionName));
        [attrEmotionString addAttribute:(NSString *)kCTRunDelegateAttributeName value:(__bridge id)(runDelegate) range:range];
        CFRelease(runDelegate);
        
    }
    //设置字体大小
     CGFloat fontSize = [USER_DEFAULT floatForKey:@"messageFontSize"];
    CTFontRef theFont = CTFontRefCTFontCreateFromUIFont([UIFont systemFontOfSize:fontSize]);
    
    CFAttributedStringSetAttribute((CFMutableAttributedStringRef)(attrEmotionString),
                                   CFRangeMake(0,CFAttributedStringGetLength((CFAttributedStringRef)(attrEmotionString))),
                                   kCTFontAttributeName,
                                   theFont);
    CFRelease(theFont);
    
    //设置字间距
    long number = kCharacterSpacing;
    CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
    [attrEmotionString addAttribute:(id)kCTKernAttributeName value:(__bridge id)num range:NSMakeRange(0,CFAttributedStringGetLength((CFAttributedStringRef)(attrEmotionString)))];
    CFRelease(num);
    
    typesetter = CTTypesetterCreateWithAttributedString((CFAttributedStringRef)(attrEmotionString));
    
    CGFloat w = mWidth;
    CGFloat y = 0;
    CFIndex start = 0;
    NSInteger length = [attrEmotionString length];
    CGFloat maxWidth = 0;
    while (start < length)
    {
        CFIndex count = CTTypesetterSuggestClusterBreak(typesetter, start, w);
        
        CGFloat ascent, descent, leading, width;
        
        
        
        CTLineRef line = CTTypesetterCreateLine(typesetter, CFRangeMake(start, count));
        
        width = CTLineGetTypographicBounds(line, &ascent,  &descent, &leading);
        CFRelease(line);
        if(width > maxWidth)
		{
			maxWidth = width;
		}
        
        start += count;
//        y-=EmotionImageWidth;
        y-= [USER_DEFAULT floatForKey:@"messageFontSize"]+4;
        
    }
    CGFloat height = -y+1;
    CFRelease(typesetter);
    //NSLog(@"CGSize(%f,%f)",maxWidth,height);
    return CGSizeMake(maxWidth, height);
}

// 翻转坐标系
static inline
void Flip_Context(CGContextRef context, CGFloat offset) // offset为字体的高度
{
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -offset);
}

// 生成每个表情的 frame 坐标
static inline
CGPoint Emoji_Origin_For_Line(CTLineRef line, CGPoint lineOrigin, CTRunRef run)
{
    CGFloat x = lineOrigin.x + CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL) + ImageLeftPadding;
    CGFloat y = lineOrigin.y - ImageTopPadding;
    return CGPointMake(x, y);
}


// 绘制每行中的表情
void Draw_Emoji_For_Line(CGContextRef context, CTLineRef line, id owner, CGPoint lineOrigin)
{
    CFArrayRef runs = CTLineGetGlyphRuns(line);
    // 统计有多少个run
    NSUInteger count = CFArrayGetCount(runs);
    // 遍历查找表情run
    for(NSInteger i = 0; i < count; i++)
    {
        CTRunRef aRun = CFArrayGetValueAtIndex(runs, i);
        CFDictionaryRef attributes = CTRunGetAttributes(aRun);
        NSString *emojiName = (NSString *)CFDictionaryGetValue(attributes, AttributedImageNameKey);
        if (emojiName)
        {
            // 画表情
            CGRect imageRect = CGRectZero;
            imageRect.origin = Emoji_Origin_For_Line(line, lineOrigin, aRun);
//            imageRect.size = CGSizeMake(EmotionImageWidth, EmotionImageWidth);
            imageRect.size = CGSizeMake([USER_DEFAULT floatForKey:@"messageFontSize"]+4, [USER_DEFAULT floatForKey:@"messageFontSize"]+4);
            CGImageRef img = [[owner getEmotionForKey:emojiName] CGImage];
            CGContextDrawImage(context, imageRect, img);
        }
    }
}

- (CGSize) measureFrame: (CTFrameRef) frame
{
	CGPathRef framePath = CTFrameGetPath(frame);
	CGRect frameRect = CGPathGetBoundingBox(framePath);
    
	CFArrayRef lines = CTFrameGetLines(frame);
	CFIndex numLines = CFArrayGetCount(lines);
    
	CGFloat maxWidth = 0;
	CGFloat textHeight = 0;
    
	// Now run through each line determining the maximum width of all the lines.
	// We special case the last line of text. While we've got it's descent handy,
	// we'll use it to calculate the typographic height of the text as well.
	CFIndex lastLineIndex = numLines - 1;
	for(CFIndex index = 0; index < numLines; index++)
	{
		CGFloat ascent, descent, leading, width;
		CTLineRef line = (CTLineRef) CFArrayGetValueAtIndex(lines, index);
		width = CTLineGetTypographicBounds(line, &ascent,  &descent, &leading);
        
		if(width > maxWidth)
		{
			maxWidth = width;
		}
        
		if(index == lastLineIndex)
		{
			// Get the origin of the last line. We add the descent to this
			// (below) to get the bottom edge of the last line of text.
			CGPoint lastLineOrigin;
			CTFrameGetLineOrigins(frame, CFRangeMake(lastLineIndex, 1), &lastLineOrigin);
            
			// The height needed to draw the text is from the bottom of the last line
			// to the top of the frame.
			textHeight =  CGRectGetMaxY(frameRect) - lastLineOrigin.y + descent;
		}
	}
    
	// For some text the exact typographic bounds is a fraction of a point too
	// small to fit the text when it is put into a context. We go ahead and round
	// the returned drawing area up to the nearest point.  This takes care of the
	// discrepencies.
	return CGSizeMake(ceil(maxWidth), ceil(textHeight));
}
- (void)setSelectedToShowCopyMenu:(BOOL)isSelected
{
    selectedToShowCopyMenu = isSelected;
    [self setNeedsDisplay];
}

#pragma mark - 响应点击事件
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // never return self. always return the result of [super hitTest..].
    // this takes userInteraction state, enabled, alpha values etc. into account
    UIView *hitResult = [super hitTest:point withEvent:event];
    // don't check for links if the event was handled by one of the subviews
    if (hitResult != self) {
        return hitResult;
    }
    
    if (_activeLink) {
        _activeLink = nil;
    }
    _activeLink = [self linkAtPoint:point];
    
    if (!_activeLink) {
        // not catch the touch if it didn't hit a link
        return nil;
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // we're using activeLink to draw a highlight in -drawRect:
    if (_activeLink && [_activeLink range].location != NSNotFound) {
//        [self setNeedsDisplay];
        if (_activeLink.resultType == NSTextCheckingTypeLink) {
            NSString *phoneRegex = @"^((https://)|(http://)|(items://)(ftp://))";
            NSRegularExpression *phoneTest = [NSRegularExpression regularExpressionWithPattern:phoneRegex options:NSRegularExpressionCaseInsensitive error:nil];
            NSTextCheckingResult *range = [phoneTest firstMatchInString:_activeLink.selectStr options:0 range:NSMakeRange(0, _activeLink.selectStr.length)];
            if (range) {
               [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[M_STOREVALUE(_activeLink.selectStr) stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
            } else {
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[[NSString stringWithFormat:@"http://%@",M_STOREVALUE(_activeLink.selectStr)] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
            }
            
        }
        else if (_activeLink.resultType == NSTextCheckingTypePhoneNumber)
        {
            UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:[NSString stringWithFormat:@"%@可能是一个电话号码,你可以",_activeLink.selectStr] delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"呼叫" otherButtonTitles:@"复制",@"保存到通讯录", nil];
            actionSheet.tag = kPhoneSheetTag;
            //隐藏bug
//            [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
            [actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
            
        }
    }
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//    if (_activeLink) {
//        _activeLink = nil;
//    }
//    if ([_activeLink range].location != NSNotFound) {
//        [self setNeedsDisplay];
//    }
}

-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
//    if (_activeLink) {
//        _activeLink = nil;
//    }
//    if ([_activeLink range].location != NSNotFound) {
//        [self setNeedsDisplay];
//    }
}

-(CBTextCheckingResult*)linkAtCharacterIndex:(CFIndex)idx {
    
    if (![self.linkDetectorArr count]) return nil;
    for (CBTextCheckingResult *result in self.linkDetectorArr) {
        NSRange r = result.range;
        if (NSLocationInRange(idx, r)) {
            return result;
        }
    }
    return nil;
}

-(CBTextCheckingResult*)linkAtPoint:(CGPoint)point {
    static const CGFloat kVMargin = 5.f;
    if (!CGRectContainsPoint(CGRectInset(self.bounds, 0, -kVMargin), point)) return nil;
    
    if (!self.drawLinesArr.count) return nil;
    CFIndex idx = NSNotFound;
    for (int lineIndex=0 ; lineIndex<self.drawLinesArr.count ; lineIndex++) {
        // this actually the origin of the line rect, so we need the whole rect to flip it
        NSDictionary *dic = _drawLinesArr[lineIndex];
        CTLineRef line = (__bridge CTLineRef)([dic objectForKey:@"line"]);

        
        CGPoint lineOrigin = CGPointMake(0, -[[dic objectForKey:@"y"] floatValue]);
        // Get bounding information of line
        CGFloat ascent = 0.0f, descent = 0.0f, leading = 0.0f;
        CGFloat width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
        CGFloat yMin = (CGFloat)floor(lineOrigin.y - descent);
        CGFloat yMax = (CGFloat)ceil(lineOrigin.y + ascent);
        // Check if we've already passed the line
        if (point.y < yMin) {
            break;
        }

        // Check if the point is within this line vertically
        if (point.y <= yMax) {
            // Check if the point is within this line horizontally
            if (point.x >= lineOrigin.x && point.x <= lineOrigin.x + width) {
                // Convert CT coordinates to line-relative coordinates
                CGPoint relativePoint = CGPointMake(point.x - lineOrigin.x, point.y - lineOrigin.y);
                idx = CTLineGetStringIndexForPosition(line, relativePoint);
                continue;
            }
        }
        
    }
    if(idx != NSNotFound)
    {
        CBTextCheckingResult* link = nil;
        link = ([self linkAtCharacterIndex:idx]);
        if (link) return link;
    }
    return nil;
}
//#pragma mark - actionDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
    if (actionSheet.tag == kPhoneSheetTag)
    {
        switch (buttonIndex) {
            case 0:
            {
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tel:%@", M_STOREVALUE(_activeLink.selectStr)]]];
   
            }
                break;
            case 1:
            {
               [UIPasteboard generalPasteboard].string = M_STOREVALUE(_activeLink.selectStr);
            }
                break;
            case 2:
            {
                [[NSNotificationCenter defaultCenter] postNotificationName:CBEMOTIONSAVEPHONE object:nil userInfo:@{@"phone":_activeLink.selectStr}];
            }
                break;
            default:
                break;
        }
    }
}


@end
